package com.xuecheng.publish.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xuecheng.api.content.model.dto.TeachplanDTO;
import com.xuecheng.common.enums.content.CourseModeEnum;
import com.xuecheng.common.exception.ExceptionCast;
import com.xuecheng.common.util.JsonUtil;
import com.xuecheng.publish.common.constant.CoursePublishErrorCode;
import com.xuecheng.publish.common.util.QiniuUtils;
import com.xuecheng.publish.entity.CourseMarket;
import com.xuecheng.publish.entity.CoursePub;
import com.xuecheng.publish.entity.CoursePubMsg;
import com.xuecheng.publish.mapper.CoursePubMapper;
import com.xuecheng.publish.service.CoursePubService;
import freemarker.template.Configuration;
import freemarker.template.Template;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.ui.freemarker.FreeMarkerTemplateUtils;
import org.springframework.util.ObjectUtils;
import com.xuecheng.publish.common.constant.CoursePubTemplateKey;

import java.util.HashMap;
import java.util.Map;

/**
 * <p>
 * 课程发布 服务实现类
 * </p>
 *
 * @author itcast
 */
@Slf4j
@Service
public class CoursePubServiceImpl extends ServiceImpl<CoursePubMapper, CoursePub> implements CoursePubService {

    @Autowired
    private Configuration configuration;
    /*
    #生成静态化页面发布位置
    course.publish.position = pages/
    #七牛云的存储消息
    file.qiniu.accessKey = pFcOu02W6CdSqjY6qmRH1jz--pwfQEVyuM4RkBGC
    file.qiniu.secretKey = z4CqmQb9LYD3AiuViX3ADk3r3-iOAm9yQePGP6Hh
    file.qiniu.bucket = xc134-staitc-pages
        * */

    @Value("${file.qiniu.accessKey}")
    private String accessKey;
    @Value("${file.qiniu.secretKey}")
    private String secretKey;
    @Value("${file.qiniu.bucket}")
    private String bucket;
    @Value("${course.publish.position}")
    private String position;
    /*
    *
    * 业务分析：
    *   0.是否开启事务
    *   1.判断消息幂等性
    *       数据标识：CoursePub中的isPub（0：发布，1：未发布）
    *   2.生成课程详情页面
    *       2.1.获得CoursePub数据，构建数据模型
    *       2.2.获得页面模板（Freemarker）
    *       2.3.生成课程详情页面html内容
    *   3.修改课程发布的状态数据
    *       将CoursePub中的isPub改为：0
    *
    *   PS：由于项目环境使用的是SpringBoot对rabbitmq的封装，如果需要消息重试：抛出异常
    *       重试条件：
    *           1.不稳定因素一起的错误，需要进行重试
    *           2.他如果是数据上的问题或其他框架的问题错误，只做错误的记录，不要重试
    *
    * */
    @Transactional
    public void publishPage(CoursePubMsg coursePubMsg) {

        //1.判断消息幂等性
        //    数据标识：CoursePub中的isPub（0：发布，1：未发布）
        LambdaQueryWrapper<CoursePub> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(CoursePub::getId,coursePubMsg.getPubId());
        queryWrapper.eq(CoursePub::getIsPub,CoursePub.IS_PUB);

        int count = this.count(queryWrapper);
        //判断课程发布的状态是否修改，如果修改说明消费方已处理完毕，无需操作
        if(count==1){
            log.warn("该课程发布消息已经处理完成，coursepubid:{}",coursePubMsg.getPubId());
            return;
        }


        //2.生成课程详情页面
        //    2.1.获得CoursePub数据，构建数据模型


        CoursePub coursePub = this.getById(coursePubMsg.getPubId());

        if(ObjectUtils.isEmpty(coursePub)){
            //错误消息需要记录，不需要抛出异常
            log.error(CoursePublishErrorCode.E_120203.getCode()+" coursePubId{}",coursePubMsg.getPubId());
            return;
        }

        Map<String, Object> dataMap=generateDataMap(coursePub);
        String htmlString=null;


        try {
            //    2.2.获得页面模板（Freemarker）
            Template template = configuration.getTemplate("learning_article.ftl");
            //    2.3.生成课程详情页面html内容
            htmlString = FreeMarkerTemplateUtils.processTemplateIntoString(template, dataMap);
        }catch (Exception e){
            log.error(CoursePublishErrorCode.E_120209.getDesc()+" coursePubid:{}",coursePubMsg.getPubId());
            return;
        }

        //将生成后的html页面上传到cdn服务上

        //课程详情页面:coursePubid.html
        try {
            String htmlName=coursePubMsg.getPubId()+".html";

            String fileKey=position+htmlName;

            QiniuUtils.upload2Qiniu(accessKey,secretKey,bucket,htmlString,fileKey);
        }catch (Exception e){
            log.error(CoursePublishErrorCode.E_120210.getDesc()+" coursePubId:{}",coursePubMsg.getPubId());
            ExceptionCast.cast(CoursePublishErrorCode.E_120210);
        }


        //3.修改课程发布的状态数据
        //    将CoursePub中的isPub改为：0
        LambdaUpdateWrapper<CoursePub> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(CoursePub::getIsPub,CoursePub.IS_PUB);
        updateWrapper.eq(CoursePub::getId,coursePubMsg.getPubId());
        queryWrapper.eq(CoursePub::getId,coursePubMsg.getPubId());

        boolean result = this.update(updateWrapper);
        if(!result){
            log.error(CoursePublishErrorCode.E_120212.getDesc()+" coursePubId：{}",coursePubMsg.getPubId());
        }


    }

    private Map<String, Object> generateDataMap(CoursePub coursePub) {

        // 1.构建数据模型dataMap
        HashMap<String, Object> dataMap = new HashMap<>();

        // 课程发布
        dataMap.put(CoursePubTemplateKey.COURSEPUB,coursePub);

        // 课程营销
        String marketJsonString = coursePub.getMarket();
        CourseMarket courseMarket = JsonUtil.jsonToObject(marketJsonString, CourseMarket.class);

        dataMap.put(CoursePubTemplateKey.COURSEMARKET,courseMarket);


        // 课程计划
        String teachplanJsonString = coursePub.getTeachplan();
        TeachplanDTO teachplanDTO = JsonUtil.jsonToObject(teachplanJsonString, TeachplanDTO.class);

        dataMap.put(CoursePubTemplateKey.TEACHPLANNODE,teachplanDTO);


        // 课程模式
        CourseModeEnum[] values = CourseModeEnum.values();
        dataMap.put(CoursePubTemplateKey.COURSETEACHMODEENUMS,values);


        // 课程教师
        // String teachersJsonString = coursePub.getTeachers();
        // List<CourseTeacher> teachers = JsonUtil.jsonToList(teachersJsonString, CourseTeacher.class);

        // dataMap.put(CoursePubTemplateKey.TEACHERS,teachers);


        return dataMap;
    }
}
